
#include "stdafx.h"
#include "JpegEncoder.h"

#pragma unmanaged

#include <fstream>
#include <memory.h>


namespace DDesktopServer{
	JpegEncoder::JpegEncoder()
	{
		m_data_buf = NULL;
		m_data_length = 0;
	}

	JpegEncoder::~JpegEncoder()
	{
		if(m_data_buf != NULL){
			delete [] m_data_buf;
		}
	}

	bool JpegEncoder::Init(int width, int height)
	{
		m_image_width = width;
		m_image_height = height;

		ejpgl::writejpegheader(&m_jpeg_header, width, height);
		m_data_buf = new unsigned char[width * height * SRC_BYTES_PER_PIXEL];
		if(m_data_buf == NULL){
			return false;
		}

		ejpgl::vlc_init_start(m_data_buf);

		return true;
	}

	const unsigned char* JpegEncoder::GetHeader(void) const
	{
		return (unsigned char*)&(m_jpeg_header);
	}


	const unsigned char* JpegEncoder::GetData(void) const
	{
		return &(m_data_buf[0]);
	}


	int JpegEncoder::GetHeaderSize(void) const
	{
		return sizeof(m_jpeg_header);
	}

	int JpegEncoder::GetDataSize(void) const
	{
		return m_data_length;
	}


	bool JpegEncoder::Encode(char* data, int size)
	{
		signed char YMatrix[MATRIX_SIZE][MATRIX_SIZE];
		signed char CrMatrix[MATRIX_SIZE][MATRIX_SIZE];
		signed char CbMatrix[MATRIX_SIZE][MATRIX_SIZE];
		signed short dctresult[MATRIX_SIZE][MATRIX_SIZE];
		signed char bitstream[NUMBER_OF_PIXELS];

		int sample;
		unsigned int col, cols, row, rows;

		signed char *src;
	 
		rows = m_image_height >> 4;  // height / 16
		cols = m_image_width >> 4;   // width / 16

		ejpgl::vlc_init_start(m_data_buf);
		
		src = (signed char*)data;
		for (row = 0; row < rows; row++) {
			for (col = 0; col < cols; col++) {
				for(sample = 0; sample < 4; sample++) {
					ejpgl::RGB2YCrCb(src, (signed char*)YMatrix, (signed char*)CrMatrix, (signed char*)CbMatrix, sample, m_image_width);
					ejpgl::dct(YMatrix, dctresult, 0);
					ejpgl::zzq_encode(dctresult, bitstream, 0);
					ejpgl::EncodeDataUnit(bitstream, 0);
				}
				ejpgl::dct(CrMatrix, dctresult, 1);
				ejpgl::zzq_encode(dctresult, bitstream, 1);
				ejpgl::EncodeDataUnit(bitstream, 1);

				ejpgl::dct(CbMatrix, dctresult, 2);
				ejpgl::zzq_encode(dctresult, bitstream, 2);
				ejpgl::EncodeDataUnit(bitstream, 2);

				src += MACRO_BLOCK_SIZE * SRC_BYTES_PER_PIXEL;
			}
			src -= SRC_BYTES_PER_PIXEL * m_image_width;
			src += MACRO_BLOCK_SIZE * SRC_BYTES_PER_PIXEL * m_image_width;
		}

		m_data_length = ejpgl::vlc_stop_done();

		return true;
	}


	// for debug
	bool JpegEncoder::WriteToFile(const char* file_name) const
	{
		std::ofstream fout(file_name, std::ios_base::binary);

		fout.write((const char*)this->GetHeader(), this->GetHeaderSize());
		fout.write((const char*)this->GetData(), this->GetDataSize());

		fout.close();

		return true;
	}
}
